#include "Test.Application.h"

#undef  APP_NAME
#define APP_NAME	TestHwCamera
#undef  APP_BASE
#define APP_BASE	TestApp


class APP_NAME : public APP_BASE
{
protected:
	BatchMaterial			material;
	float					angle;

	Ptr< HardwareCamera >	hwCamera;


public:
	APP_NAME (IPlatform *platform, EDevice::type deviceType) :
		APP_BASE( platform, deviceType ), angle(0.0f)
	{}


	void Update (float dt) override
	{
		TestApp::Update( dt );

		ESS()->GetGraphicsEngine()->GetViewport()->Apply();
		ESS()->GetGLStateManager()->ClearColor( color4f( 0.0f, 0.0f, 1.0f, 1.0f ) );

		ESS()->GetGraphicsEngine()->GetRender2D().DrawRectRotated( material, vec2(0.0f), vec2(2.0f), color4u(255), angle, true );

		batch.Flush();
		batch.Clear();
		
		ESS()->GetGraphicsEngine()->SwapBuffers();
	}


	void OnEnter () override
	{
		APP_BASE::OnEnter();

		TexturePtr	yTexture  = Texture::New( ESS() );
		TexturePtr	uvTexture = Texture::New( ESS() );

		ProgramPtr	program;

		ESS()->GetResourceManager()->Load( EResource::PROGRAM, "prog/camera_nv21", program );

		material.SetTexture( 0, yTexture );
		material.SetTexture( 1, uvTexture );
		material.SetProgram( program );
		
		hwCamera = GetPlatform()->GetCamera();

		if ( hwCamera.IsNotNull() )
		{
			hwCamera->Open();
			hwCamera->SetPreviewCallback( HardwareCamera::OnImageCallback_t( &OnPreview, this ) );
		}
	}
	

	void OnExit () override
	{
		if ( hwCamera.IsNotNull() )
		{
			hwCamera->SetPreviewCallback( HardwareCamera::OnImageCallback_t() );
			hwCamera->Close();
			hwCamera = null;
		}
		material.Clear();
		APP_BASE::OnExit();
	}


	static void OnPreview (const BaseObjectPtr &obj, const uni_binbuffer_t &data, const ivec2 &dim, HardwareCamera::ImageFormat::type fmt)
	{
		APP_NAME *	app = obj.ToPtr< APP_NAME >();

		const ivec2	vp_size = app->GetSubSystems()->GetGraphicsEngine()->GetViewport()->Size();

		bool	wide_tex = dim.x > dim.y;
		bool	wide_vp  = vp_size.x > vp_size.y;

		if ( wide_tex != wide_vp ) {
			app->angle = -Pi<float>() * 0.5f;
		}
		else {
			app->angle = 0.0f;
		}

		TexturePtr	ytex  = Texture::New( app->GetSubSystems() );
		TexturePtr	uvtex = Texture::New( app->GetSubSystems() );

		ytex->SetImage( uvec3( dim.x, dim.y, 0 ), EPixelFormat::ALPHA8, 0, data );
		uvtex->SetImage( uvec3( dim.x, dim.y, 0 ) / 2, EPixelFormat::RG8, 0, data.SubArray( dim.x * dim.y ) );

		app->material.SetTexture( 0, ytex );
		app->material.SetTexture( 1, uvtex );
	}
};